/*
 * pid.h
 *
 * Copyright 2011 Pieter Agten
 *
 * This file is part of Yarf.
 *
 * Yarf is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Yarf is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Yarf.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file   pid.h
 * @author Pieter Agten (pieter.agten@gmail.com)
 * @date   28 okt 2011
 * @brief  The proportional–integral–derivative algorithm controls the amount
 *         of power delivered to the nozzle and printbed heaters, in order to
 *         keep them at their required temperature, without too much
 *         fluctuation.
 */

#ifndef PID_H_
#define PID_H_

#include <stdint.h>

/**
 * Datastructure for an instance of the PID algorithm
 */
typedef struct {
  uint8_t envelope;   /**< Number of degrees above or below the target temperature, at which the PID algorithm kicks in. */
  uint8_t p_gain;     /**< Gain of the proportional component. */
  uint8_t i_gain;     /**< Gain of the integral component. */
  uint8_t d_gain;     /**< Gain of the derivative component. */
  
  float i_state;      /**< Accumulated state of the integral component. */
  float d_term;       /**< Previous value of the derivative term, required to calculate the new value of the derivative term. */
  float target_temp;  /**< Target temperature in degrees celsius. */
  float last_temp;    /**< Previously measured temperature in degrees celsius. */
} pid_t;

/**
 * Initializes an instance of the PID algorithm.
 *
 * @param pid       pointer to the instance of the PID algorithm to initialize
 * @param envelope  number of degrees above or below the target temperature, at
 *                  which the PID algorithm kicks in. Outside of this
 *                  temperature range, \a pid_next returns 0 if the temperature
 *                  is too high and 255 if it is too low.
 * @param p         gain of the proportional component for the given PID
 *                  instance
 * @param i         gain of the integral component for the given PID instance
 * @param d         gain of the derivative component for the given PID instance
 */
void pid_init(pid_t *pid, uint8_t envelope, uint8_t p, uint8_t i, uint8_t d);

/**
 * Sets the target temperature for a given PID algorithm instance.
 *
 * @param pid          pointer to the PID instance of which to set the target
 *                     temperature
 * @param target_temp  target temperature in degrees celcius
 */
void pid_set_target(pid_t *pid, float target_temp);

/**
 * Returns the next result of a given PID algorithm instance, given the current
 * measured temperature. The result indicates the amount of power to apply to
 * heater belonging to the given PID instance. This function should be called 
 * at short periodic intervals.
 *
 * @param pid           pointer to the PID instance for which to return the
 *                      next result
 * @param current_temp  the current measured temperature in degrees celsius
 * @return An integer between 0 and 255, indicating the relative amount of 
 *         power to apply to the heater belonging to the given PID instance, in
 *         order to reach the instance's target temperature.
 */
uint8_t pid_next(pid_t *pid, float current_temp);

#endif //PID_H_
